package com.cui.project.mq;

import com.api.common.alert.CommonAlertHelper;
import com.api.common.constant.APIInterfaceMqConstant;
import com.api.common.model.dto.InvokeCountCompensation;
import com.cui.project.service.UserInterfaceInfoService;
import com.google.gson.Gson;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;


/**
 * @Description: 接口调用次数补偿消息消费者
 */
@Slf4j
@Component
public class CompensateMessageConsumer {

    @Resource
    private UserInterfaceInfoService userInterfaceInfoService;

    @Resource
    private CommonAlertHelper  alertHelper;

    /**
     * 最大重试次数
     */
    private static final int MAX_RETRY_COUNT = 3;
    @RabbitListener(queues = {APIInterfaceMqConstant.API_INVOKE_COUNT_COMPENSATION_QUEUE},ackMode = "MANUAL")
    public void receiveCompensationMessage(String message, Channel channel,
                                           @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
        log.info("收到调用次数补偿消息: deliveryTag={}, message={}", deliveryTag, message);
        if(StringUtils.isBlank(message)){
            try {
                // 空消息直接拒绝，不重新入队
                channel.basicNack(deliveryTag,false,false);
                log.warn("收到空的补偿消息，已拒绝");
            } catch (IOException e) {
                log.error("拒绝空消息失败", e);
            }
            return;
        }
        Gson gson=new Gson();
        InvokeCountCompensation compensation=null;
        try {
            compensation=gson.fromJson(message, InvokeCountCompensation.class);

            if(compensation==null||compensation.getInterfaceInfoId()==null || compensation.getUserId()==null){
                log.error("补偿消息缺少必要字段：{}",message);
                channel.basicNack(deliveryTag,false,false);
                return;
            }

            Long interfaceInfoId = compensation.getInterfaceInfoId();
            Long userId = compensation.getUserId();
            int retryCount = compensation.getRetryCount() == null ? 0 : compensation.getRetryCount();

            //检查重试次数
            if(retryCount>=MAX_RETRY_COUNT){
                log.error("补偿消息重试次数超过最大值({})，放弃补偿: interfaceInfoId={}, userId={}, requestId={}",
                        MAX_RETRY_COUNT, interfaceInfoId, userId, compensation.getRequestId());
                saveToFailedCompensationLog(compensation);
                channel.basicNack(deliveryTag,false,false);
                return;
            }

            log.info("开始执行补偿扣款: interfaceInfoId={}, userId={}, retryCount={}, requestId={}",
                    interfaceInfoId, userId, retryCount, compensation.getRequestId());

            int success = userInterfaceInfoService.invokeCount(
                    interfaceInfoId,
                    userId
            );

            if(success>0){
                //补偿成功
                channel.basicAck(deliveryTag,false);
                log.info("补偿扣款成功: interfaceInfoId={}, userId={}, requestId={}",
                        compensation.getInterfaceInfoId(),
                        compensation.getUserId(),
                        compensation.getRequestId());
            }else{
                // 补偿失败，重新入队
                handleCompensationFailure(compensation, channel, deliveryTag, "补偿扣款返回失败");
            }

        }catch (Exception e){
            log.error("处理补偿消息异常: deliveryTag={}, message={}", deliveryTag, message, e);

            try {
                if (compensation != null) {
                    handleCompensationFailure(compensation, channel, deliveryTag, e.getMessage());
                } else {
                    // 解析失败，不重新入队
                    channel.basicNack(deliveryTag, false, false);
                }
            } catch (IOException ioException) {
                log.error("处理补偿消息失败后的Nack操作异常", ioException);
            }
        }
    }

    /**
     * 处理补偿失败的情况
     */
    private void handleCompensationFailure(InvokeCountCompensation compensation,
                                           Channel channel,
                                           long deliveryTag,
                                           String errorMessage) throws IOException {
        int currentRetryCount = compensation.getRetryCount() == null ? 0 : compensation.getRetryCount();

        if (currentRetryCount < MAX_RETRY_COUNT - 1) {
            // 还可以重试，重新入队
            compensation.setRetryCount(currentRetryCount + 1);
            compensation.setErrorMessage(errorMessage);
            channel.basicNack(deliveryTag, false, true);
            log.warn("补偿失败，将重新入队: interfaceInfoId={}, userId={}, retryCount={}/{}, requestId={}",
                    compensation.getInterfaceInfoId(),
                    compensation.getUserId(),
                    currentRetryCount + 1,
                    MAX_RETRY_COUNT,
                    compensation.getRequestId());
        } else {
            // 达到最大重试次数，记录到失败日志
            compensation.setRetryCount(currentRetryCount + 1);
            compensation.setErrorMessage(errorMessage);
            saveToFailedCompensationLog(compensation);
            channel.basicNack(deliveryTag, false, false);
            log.error("❌ 补偿失败且达到最大重试次数: interfaceInfoId={}, userId={}, requestId={}",
                    compensation.getInterfaceInfoId(),
                    compensation.getUserId(),
                    compensation.getRequestId());
        }
    }


    /**
     * 保存失败的补偿记录（可以存入数据库或文件系统）
     */
    private void saveToFailedCompensationLog(InvokeCountCompensation compensation) {
        // TODO: 实现保存到数据库的逻辑，用于后续人工处理
        log.error("补偿最终失败，需人工介入处理: {}", new Gson().toJson(compensation));
        // 可以保存到专门的失败补偿表，或者发送告警通知运维人员
        alertHelper.mqConsumeFailure(
                APIInterfaceMqConstant.API_INVOKE_COUNT_COMPENSATION_QUEUE,
                compensation.getRequestId(),
                String.format("补偿失败达到最大重试次数(%d次), userId=%d, interfaceId=%d",
                        MAX_RETRY_COUNT,
                        compensation.getUserId(),
                        compensation.getInterfaceInfoId()),
                        "195883938@qq.com"  // 运维团队邮箱"
        );
    }

}
